/**
 * 文件名：****.java
 * 版权：Copyright Lightkit All Rights Reserved.
 * 描述：*****
 */
package com.lightkits.wms.domain.nontaskpickinglist.service.impl;

import com.lightkits.common.TransactionValidate;
import com.lightkits.common.db.entity.BdMoBase;
import com.lightkits.common.db.entity.FndItemBase;
import com.lightkits.common.db.entity.FndOrganizationBase;
import com.lightkits.common.db.entity.FndProductionLine;
import com.lightkits.common.db.entity.FndWarehouse;
import com.lightkits.common.db.entity.FndWmArea;
import com.lightkits.common.db.entity.FndWorkcell;
import com.lightkits.common.db.entity.FndWorker;
import com.lightkits.common.db.entity.WmRequestHeader;
import com.lightkits.common.db.entity.WmRequestLine;
import com.lightkits.common.db.entity.event.BdEvent;
import com.lightkits.common.db.entity.event.BdEventRecord;
import com.lightkits.framework.common.exception.LightKitsBizException;
import com.lightkits.framework.common.logging.Logger;
import com.lightkits.framework.common.logging.LoggerFactory;
import com.lightkits.framework.common.model.CheckResult;
import com.lightkits.framework.common.model.IResult;
import com.lightkits.framework.common.utility.date.DateUtil;
import com.lightkits.framework.common.utility.object.ObjectUtil;
import com.lightkits.framework.common.utility.validate.IntegrityValidator;
import com.lightkits.wms.domain.nontaskpickinglist.repo.WmRequestHeaderService;
import com.lightkits.wms.domain.nontaskpickinglist.repo.WmRequestLineService;
import com.lightkits.wms.domain.nontaskpickinglist.service.CreateNonTaskPickDomain;
import com.lightkits.wms.domain.nontaskpickinglist.service.CreateNonTaskPickParams;
import com.lightkits.wms.domain.saveonhand.repo.BdEventRecordService;
import com.lightkits.wms.domain.saveonhand.repo.BdEventService;
import com.lightkits.wms.dto.nontaskpicking.model.PickingHeaderDTO;
import com.lightkits.wms.dto.nontaskpicking.model.PickingLineDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * CreateNonTaskPickDomainImpl
 *
 * @author jing.wei@hand-china.com
 * Created on 2019/5/9 14:40
 */
@Service
public class CreateNonTaskPickDomainImpl implements CreateNonTaskPickDomain {

    private final Logger logger = LoggerFactory.getLogger(CreateNonTaskPickDomainImpl.class);

    private final CreateNonTaskPickParams createNonTaskPickParams;

    private final WmRequestHeaderService headerService;
    private final WmRequestLineService lineService;
    private final BdEventService bdEventService;
    private final BdEventRecordService bdEventRecordService;

    @Autowired
    public CreateNonTaskPickDomainImpl(CreateNonTaskPickParams createNonTaskPickParams,
                                       WmRequestHeaderService headerService,
                                       WmRequestLineService lineService,
                                       BdEventService bdEventService,
                                       BdEventRecordService bdEventRecordService) {
        this.createNonTaskPickParams = createNonTaskPickParams;
        this.headerService = headerService;
        this.lineService = lineService;
        this.bdEventService = bdEventService;
        this.bdEventRecordService = bdEventRecordService;
    }

    /**
     * 创建领料单
     *
     * @param headerDTO 领料单头
     * @param lineDTOS  领料单行
     * @return IResult
     */
    private IResult checkParams(PickingHeaderDTO headerDTO, List<PickingLineDTO> lineDTOS) {

        try {
            IntegrityValidator.begin()
                    .validate(headerDTO.getOrgId(), "Organization Id")
                    .validate(headerDTO.getCreatorId(), "Creator Id")
                    .validate(headerDTO.getOperationType(), "Operation Type")
                    .validate(headerDTO.getRequestType(), "Request Type");
            TransactionValidate check1 = TransactionValidate.beginValidity(FndOrganizationBase.class);
            check1.checkIdValidity(ObjectUtil.toString(headerDTO.getOrgId()), "ORGANIZATION_ID");

            check1 = TransactionValidate.beginValidity(BdMoBase.class);
            check1.checkIdValidity(ObjectUtil.toString(headerDTO.getMoId()), "ID");

            check1 = TransactionValidate.beginValidity(FndWorker.class);
            check1.checkIdValidity(ObjectUtil.toString(headerDTO.getRequestWorkerId()), "ID");

            check1 = TransactionValidate.beginValidity(FndWorker.class);
            check1.checkIdValidity(ObjectUtil.toString(headerDTO.getCreatorId()), "ID");

            check1 = TransactionValidate.beginValidity(FndOrganizationBase.class);
            check1.checkIdValidity(ObjectUtil.toString(headerDTO.getToOrganzationId()), "ORGANIZATION_ID");

            check1 = TransactionValidate.beginValidity(FndWorkcell.class);
            check1.checkIdValidity(ObjectUtil.toString(headerDTO.getWorkcellId()), "ID");

            check1 = TransactionValidate.beginValidity(FndProductionLine.class);
            check1.checkIdValidity(ObjectUtil.toString(headerDTO.getProdlineId()), "ID");

            if (!ObjectUtil.isNullOrEmpty(headerDTO.getDemandDate())
                    && !DateUtil.isDate(headerDTO.getDemandDate(), DateUtil.DEFAULT_DATETIME_PATTERN)) {
                return IResult.fail("the Date Format is invalid");
            }

            lineDTOS.forEach(dto -> {
                IntegrityValidator.begin()
                        .validate(dto.getItemId(), "Item Id")
                        .validate(dto.getFromWarehouseId(), "From Warehouse Id")
                        .validate(dto.getApplyQty(), "Apply Qty");

                TransactionValidate check2 = TransactionValidate.beginValidity(FndItemBase.class);
                check2.checkIdValidity(ObjectUtil.toString(dto.getItemId()), "ITEM_ID");


                check2 = TransactionValidate.beginValidity(FndWarehouse.class);
                check2.checkIdValidity(ObjectUtil.toString(dto.getFromWarehouseId()), "ID");

                check2 = TransactionValidate.beginValidity(FndWorkcell.class);
                check2.checkIdValidity(ObjectUtil.toString(dto.getFromWorkcellId()), "ID");

                check2 = TransactionValidate.beginValidity(FndWmArea.class);
                check2.checkIdValidity(ObjectUtil.toString(dto.getFromAreaId()), "ID");

                check2 = TransactionValidate.beginValidity(FndWarehouse.class);
                check2.checkIdValidity(ObjectUtil.toString(dto.getToWarehouseId()), "ID");

                check2 = TransactionValidate.beginValidity(FndWorkcell.class);
                check2.checkIdValidity(ObjectUtil.toString(dto.getToWorkcellId()), "ID");

                check2 = TransactionValidate.beginValidity(FndWmArea.class);
                check2.checkIdValidity(ObjectUtil.toString(dto.getToAreaId()), "ID");

                Pattern pattern = Pattern.compile("([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9])");
                if (!pattern.matcher(dto.getApplyQty()).matches()) {
                    throw new LightKitsBizException("The Apply Quantity is invalid");
                }
            });


        } catch (LightKitsBizException e) {
            return e.result();
        }

        return IResult.success();

    }

    /**
     * 领料单创建事务操作
     *
     * @param headerDTO   领料单头
     * @param lineDTOList 领料单行
     * @return IResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public IResult insertValue(PickingHeaderDTO headerDTO, List<PickingLineDTO> lineDTOList) {
        IResult result = this.checkParams(headerDTO, lineDTOList);
        if (!result.isSuccessful()) {
            return result;
        }
        CheckResult checkResult = createNonTaskPickParams.createRequestHeader(headerDTO);
        if (!checkResult.isSuccessful() || ObjectUtil.isEmpty(checkResult.getData())) {
            return checkResult;
        }
        WmRequestHeader header = (WmRequestHeader) checkResult.getData();
        boolean headerFlag = headerService.insert(header);
        if (!headerFlag) {
            throw new LightKitsBizException("insert Request Header Error");
        }
        checkResult = createNonTaskPickParams.createEvent(headerDTO);
        if (!checkResult.isSuccessful() || ObjectUtil.isEmpty(checkResult.getData())) {
            return checkResult;
        }
        BdEvent event = (BdEvent) checkResult.getData();
        boolean eventFlag = bdEventService.insert(event);
        if (!eventFlag) {
            throw new LightKitsBizException("insert Request Header Error");
        }

        List<BdEventRecord> records = this.getEvetRecord(event.take(), event.getId(), header.getId());
        if (ObjectUtil.isNullOrEmpty(records)) {
            throw new LightKitsBizException("Create Event Records  Error");
        }

        boolean recordsFlag = bdEventRecordService.insertBatch(records);
        if (!recordsFlag) {
            throw new LightKitsBizException("insert Event Records  Error");
        }

        checkResult = createNonTaskPickParams.createRequestLines(lineDTOList, header.getId());
        if (!checkResult.isSuccessful() || ObjectUtil.isEmpty(checkResult.getData())) {
            return checkResult;
        }
        List<WmRequestLine> lines = (List<WmRequestLine>) checkResult.getData();
        boolean linesFlag = lineService.insertBatch(lines);
        if (!linesFlag) {
            throw new LightKitsBizException("insert Request Header Error");
        }
        return IResult.success();
    }

    /**
     * @param records  快照
     * @param objectId 事件对象ID
     * @param eventId  事件ID
     * @return List<BdEventRecord>
     */
    private List<BdEventRecord> getEvetRecord(List<Object> records, Long eventId, Long objectId) {
        List<BdEventRecord> bdEventRecords = new ArrayList<>();
        try {
            for (Object object : records) {
                if (object.getClass().equals(BdEventRecord.class)) {
                    BdEventRecord record = (BdEventRecord) object;
                    record.setEventId(eventId);
                    record.setObjectId(objectId);
                    bdEventRecords.add(record);
                }
            }
        } catch (Exception e) {
            logger.error("getEventRecord.error", e);
        }
        return bdEventRecords;
    }
}
